10. Memory and the CPU

04 L C And RAM V1 RENDER V1

Stack vs Heap

Stack

When you declare a variable in C++, the variable will automatically be placed on the stack. Once a function terminates, for example the main function, then the variable is removed from the stack; however, in terms of the code you've written so far in the nanodegree, there is one exception. The elements in a vector actually get placed on the heap, but the compiler still manages the allocation and deallocation of memory for you.

The stack removes variables by the "last in first out" rule; in other words, the last variable to be placed on the stack will be the first variable removed from the stack. This makes sense given that when a function is called, variables will be allocated to memory and then when the function terminates, variables will be removed from memory.

The stack also tends to be relatively small: perhaps 1 MB depending on your system. One advantage to keeping the stack small is for multi-threading. Let's say you only have 50 MB of RAM for the stack. Your CPU could do about 50 simultaneous tasks because of the smaller stack size. But because the stack is small, the stack can run out of memory; this is called stack overflow.

Heap

The heap, on the other hand, is only limited by the amount of RAM currently available. So variables that hold a lot of memory have to go on the heap. But when you declare a variable on the heap, you are responsible for removing the variable from memory. If you don't, then it becomes more likely that your program will run out of memory before the program terminates. And then your program will crash.

The heap also tends to be slower; a compiler organizes the stack for you and knows where the next available memory slot is; on the other hand, a program might have to search for an empty spot to put a variable on the heap.

In relation to code efficiency, only use the heap when necessary. Although you will not need to use the heap in the nanodegree, you'll at least become familiar with the syntax so that you can recognize when a program is using the heap. In the next section, you'll also see a demonstration about the stack versus the heap.

Variables and Memory

Variables make programming much easier. Imagine what programming would be like if variables did not exist; you would have to determine

  • determine how many bytes your variable needs
  • find an available address to store the value
  • make sure there are enough consecutive bytes available for storage
  • you would also have to remember what value was stored at each hexadecimal address so that you could retrieve the right value as needed.

But with variables, the compiler does all of the memory management for you. And you can use descriptive names to help you remember what is contained in each variable.

This is essentially what the compiler is doing for you in terms of variables and memory management; without you having to think about it, the compiler efficiently finds space for your variables and keeps track of their location.

Dynamic Memory

To understand the next demo, you need to know about dynamic memory allocation and pointers.

Dynamic memory allocation refers to when you, the programmer, assign variables to memory manually. These variables will go on the heap rather than the stack.

The opposite of dynamic memory allocation would be static memory allocation. You've already been using static memory in your programs; when you declare variables in your programs, the compiler knows ahead of time how much memory each variable will need; the amount of memory your variables need does not change as the program executes, so this memory is "static". The stack is used for static memory allocation.

The compiler doesn't know how much memory will be needed for dynamically allocated variables; hence, dynamic memory gets allocated when you execute your programs. Dynamically allocated variables go on the heap.

To use dynamic memory, you need to be familiar with pointers and the new and delete C++ syntax. A pointer is a special type of variable that holds a memory address rather than a value. You don't need to know how to use pointers, but they show up in the demo in the next part of the lesson.

Here is an example of dynamic memory allocation using pointers:

#include <iostream>

int main() {

    // asterisk syntax creates a pointer variable, which can hold a memory address
    int * pointervariable;

    // new is used to create a variable on the heap. This line
    // assigns an addresss to pointervariable and reserves enough space
    // told hold an integer.
    pointervariable = new int;

    // Pointer variable holds an addresss. The address allows placing a value in
    // memory at the address.
    *pointervariable = 10;

    std::cout << "pointer value:  " << *pointervariable << "\n";
    std::cout << "pointer address: " << pointervariable << "\n";

    // remove pointervariable from the heap
    delete pointervariable;
    pointervariable = NULL;

    return 0;
}

With the result outputting something like:

pointer value: 10
pointer address: 0x1004053c0

although the exact memory address will differ from machine to machine. The pointer address is a hexadecimal number representing the location in memory.

The new operator assigns memory to the heap. You are are responsible for removing the variable when you are done with it, which is what the delete operator is for. Setting the pointer to NULL is good practice.

If you do not remove the variable, your program could run out of memory during execution; some operating systems might delete memory from the heap when your program terminates but some might not. Forgetting to remove dynamically allocated variables is called a memory leak.

Newer versions of C++ also include smart pointers that delete automatically when the program terminates.

Next, you'll see a demonstration of static versus dynamic memory allocation.

Stack vs Heap

When should you use dynamic memory allocation over static memory allocation?

SOLUTION:
  • If your variable uses more memory than what is available in the stack
  • If you want to share variables across different functions or parts of a program